package cn.lg.soar.system.auth.service.impl;

import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.current.CurrentProxy;
import cn.lg.soar.database.base.service.impl.NumberTreeServiceImpl;
import cn.lg.soar.system.api.enums.RoleTypeEnum;
import cn.lg.soar.system.auth.entity.*;
import cn.lg.soar.system.auth.mapper.RoleMapper;
import cn.lg.soar.system.auth.model.RoleDto;
import cn.lg.soar.system.auth.service.*;
import cn.lg.soar.system.config.AuthCacheKey;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class RoleServiceImpl extends NumberTreeServiceImpl<Long, RoleMapper, Role> implements IRoleService, CurrentProxy<IRoleService> {

    @Autowired
    private RoleMenuService roleMenuService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private OrgRoleService orgRoleService;
    @Autowired
    private PostRoleService postRoleService;

    @Override
    public Long getRootId() {
        return 0L;
    }

    @Cacheable(value = AuthCacheKey.ROLE_BY_ID, key = "#id")
    @Override
    public Role getById(Serializable id) {
        return super.getById(id);
    }

    @Override
    public List<Role> listByCodes(Collection<String> codes) {
        if (CollectionUtils.isEmpty(codes)) {
            return Collections.emptyList();
        }
        codes = codes.stream().distinct().collect(Collectors.toList());
        return this.list(
                Wrappers.<Role>lambdaQuery()
                        .select(Role::getId, Role::getCode, Role::getName)
                        .in(Role::getCode, codes)
        );
    }

    @Override
    public List<String> codesByIds(List<Long> roleIds) {
        if (CollectionUtils.isEmpty(roleIds)) {
            return Collections.emptyList();
        }
        return listObjs(
                Wrappers.<Role>lambdaQuery()
                        .select(Role::getCode)
                        .in(Role::getId, roleIds),
                Object::toString
        );
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Long create(RoleDto data) {
        Role convert = data.toRole();
        AssertUtil.isTrue(this.save(convert), "创建角色失败");
        if (data.getMenuIds() != null) {
            roleMenuService.setRoleMenu(convert.getId(), data.getMenuIds());
        }
        return convert.getId();
    }

    @CacheEvict(value = { AuthCacheKey.ROLE_BY_ID, AuthCacheKey.ROLE_ID_BY_RELEVANT}, key = "#entity.id")
    @Override
    public boolean updateById(Role entity) {
        return super.updateById(entity);
    }

    @CacheEvict(value = { AuthCacheKey.ROLE_BY_ID, AuthCacheKey.ROLE_ID_BY_RELEVANT}, key = "#id")
    @Override
    public boolean removeById(Serializable id) {
        return super.removeById(id);
    }

    @CacheEvict(value = { AuthCacheKey.ROLE_BY_ID, AuthCacheKey.ROLE_ID_BY_RELEVANT}, allEntries = true)
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public boolean removeByIds(Collection<?> list) {
        IRoleService self = this.proxy();
        for (Object id : list) {
            AssertUtil.isTrue(self.removeById((Serializable) id), "删除{0}失败", id);
        }
        userRoleService.remove(Wrappers.<UserRole>lambdaQuery().in(UserRole::getRoleId, list));
        orgRoleService.remove(Wrappers.<OrgRole>lambdaQuery().in(OrgRole::getRoleId, list));
        postRoleService.remove(Wrappers.<PostRole>lambdaQuery().in(PostRole::getRoleId, list));
        roleMenuService.remove(Wrappers.<RoleMenu>lambdaQuery().in(RoleMenu::getRoleId, list));
        return true;
    }

    @CacheEvict(value = {
            AuthCacheKey.ROLE_BY_ID,
            AuthCacheKey.ROLE_ID_BY_POST,
            AuthCacheKey.ROLE_ID_BY_ORG,
            AuthCacheKey.ROLE_ID_BY_USER,
            AuthCacheKey.ROLE_ID_BY_RELEVANT
    }, allEntries = true)
    @Override
    public void clearCache() {}

    @Cacheable(value = AuthCacheKey.ROLE_ID_BY_RELEVANT, key = "#roleId")
    @Override
    public List<Long> getRelevantIds(Long roleId) {
        if (roleId == null) {
            return Collections.emptyList();
        }
        Role role = proxy().getById(roleId);
        if (role == null) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<Role> queryWrapper;
        Integer type = role.getType();
        if (RoleTypeEnum.inheritChildren.eq(type)) {
            // 查询所有下级id
            queryWrapper = Wrappers.<Role>lambdaQuery()
                    .select(Role::getId)
                    .gt(Role::getLeftNo, role.getLeftNo())
                    .lt(Role::getRightNo, role.getRightNo());
        } else if (RoleTypeEnum.inheritParent.eq(type)) {
            // 所有上级id
            queryWrapper = Wrappers.<Role>lambdaQuery()
                    .select(Role::getId)
                    .lt(Role::getLeftNo, role.getLeftNo())
                    .gt(Role::getRightNo, role.getRightNo());
        } else {
            return Collections.emptyList();
        }
        return listObjs(queryWrapper, x -> Long.parseLong(x.toString()));
    }

}
